`CPDF_TextPage` 类是 PDFium 项目中的一个关键组件，用于解析和处理 PDF 文档中的文本内容。它能够从 PDF 页面中提取出文本信息，并为每个字符生成详细的 `CharInfo` 信息，包括字符类型、Unicode 值、原始位置、字符框、变换矩阵以及所属的 `CPDF_TextObject`。以下是该类的主要功能和方法概述：

### 枚举定义

- **`CharType`* * :
-用于表示字符的类型，如普通字符（`kNormal`）、生成字符（`kGenerated`）、非 Unicode 字符（`kNotUnicode`）、连字符（`kHyphen`）或分段字符（`kPiece`）。

- **`TextOrientation`* * :
-用于表示文本的方向，包括未知方向（`kUnknown`）、水平方向（`kHorizontal`）和垂直方向（`kVertical`）。

- **`GenerateCharacter`* * :
-用于表示生成的字符类型，如不生成字符（`kNone`）、空格（`kSpace`）、换行符（`kLineBreak`）或连字符（`kHyphen`）。

- **`MarkedContentState`* * :
-用于表示标记内容的状态，包括通过（`kPass`）、完成（`kDone`）和延迟（`kDelay`）。

### 内部类 `CharInfo`

`CharInfo` 类提供了关于单个字符的详细信息，包括但不限于字符类型、字符代码、Unicode 值、字符原点、字符框、变换矩阵和所属的 `CPDF_TextObject`。

### 公有成员函数

- **构造函数 `CPDF_TextPage(const CPDF_Page * pPage, bool rtl)`** :
-功能：创建一个 `CPDF_TextPage` 实例，接收指向 `CPDF_Page` 的指针和一个布尔值来指示是否使用从右到左的文本布局。

- **析构函数 `~CPDF_TextPage()`* * :
-功能：释放 `CPDF_TextPage` 占用的资源。

- **方法 `int CharIndexFromTextIndex(int text_index) const`* * :
-功能：将文本索引转换为字符索引。

- **方法 `int TextIndexFromCharIndex(int char_index) const`* * :
-功能：将字符索引转换为文本索引。

- **方法 `size_t size() const`* * :
-功能：返回字符列表的大小。

- **方法 `int CountChars() const`* * :
-功能：返回字符总数。

- **方法 `const CharInfo & GetCharInfo(size_t index) const`* * :
-功能：获取指定索引处的 `CharInfo`。

- **方法 `CharInfo& GetCharInfo(size_t index)`* * :
-功能：获取指定索引处的 `CharInfo`（可修改）。

- **方法 `float GetCharFontSize(size_t index) const`* * :
-功能：获取指定字符的字体大小。

- **方法 `CFX_FloatRect GetCharLooseBounds(size_t index) const`* * :
-功能：获取指定字符的宽松边界矩形。

- **方法 `std: : vector<CFX_FloatRect> GetRectArray(int start, int count) const`* * :
-功能：获取指定范围内的字符矩形数组。

- **方法 `int GetIndexAtPos(const CFX_PointF & point, const CFX_SizeF & tolerance) const`* * :
-功能：根据给定的点和容差查找最接近的字符索引。

- **方法 `WideString GetTextByRect(const CFX_FloatRect & rect) const`* * :
-功能：根据给定的矩形区域提取文本。

- **方法 `WideString GetTextByObject(const CPDF_TextObject * pTextObj) const`* * :
-功能：根据给定的 `CPDF_TextObject` 提取文本。

- **方法 `WideString GetPageText(int start, int count) const`* * :
-功能：根据给定的起始索引和字符数量提取页面文本。

- **方法 `WideString GetAllPageText() const`* * :
-功能：提取整个页面的文本。

- **方法 `int CountRects(int start, int nCount)`* * :
-功能：计算指定范围内的字符矩形数量。

- **方法 `bool GetRect(int rectIndex, CFX_FloatRect * pRect) const`* * :
-功能：获取指定索引处的字符矩形。

### 私有成员函数

- **方法 `void Init()`* * :
-功能：初始化 `CPDF_TextPage` 实例。

- **方法 `bool IsHyphen(wchar_t curChar) const`* * :
-功能：检查给定字符是否为连字符。

- **方法 `void ProcessObject()`* * :
-功能：处理 PDF 页面对象。

- **方法 `void ProcessFormObject(CPDF_FormObject * pFormObj, const CFX_Matrix & form_matrix)`* * :
-功能：处理表单对象。

- **方法 `void ProcessTextObject(const TransformedTextObject & obj)`* * :
-功能：处理已变换的文本对象。

- **方法 `void ProcessTextObject(CPDF_TextObject * pTextObj, const CFX_Matrix & form_matrix, const CPDF_PageObjectHolder * pObjList, CPDF_PageObjectHolder::const_iterator ObjPos)`* * :
-功能：处理文本对象。

- **方法 `GenerateCharacter ProcessInsertObject(const CPDF_TextObject * pObj, const CFX_Matrix & form_matrix)`* * :
-功能：处理插入对象并返回生成的字符类型。

- **方法 `bool ProcessGenerateCharacter(GenerateCharacter type, const CPDF_TextObject * text_object, const CFX_Matrix & form_matrix)`* * :
-功能：处理生成字符并返回是否继续处理。

- **方法 `void ProcessTextObjectItems(CPDF_TextObject * text_object, const CFX_Matrix & form_matrix, const CFX_Matrix & matrix)`* * :
-功能：处理文本对象的项。

- **方法 `const CharInfo * GetPrevCharInfo() const`* * :
-功能：获取前一个字符信息。

- **方法 `std: : optional<CharInfo> GenerateCharInfo(wchar_t unicode, const CFX_Matrix & form_matrix)`* * :
-功能：生成字符信息。

- **方法 `bool IsSameAsPreTextObject(CPDF_TextObject * pTextObj, const CPDF_PageObjectHolder * pObjList, CPDF_PageObjectHolder::const_iterator iter) const`* * :
-功能：检查当前文本对象是否与前一个相同。

- **方法 `bool IsSameTextObject(CPDF_TextObject * pTextObj1, CPDF_TextObject * pTextObj2) const`* * :
-功能：检查两个文本对象是否相同。

- **方法 `void CloseTempLine()`* * :
-功能：关闭临时行。

- **方法 `MarkedContentState PreMarkedContent(const CPDF_TextObject * pTextObj)`* * :
-功能：预处理标记内容。

- **方法 `void ProcessMarkedContent(const TransformedTextObject & obj)`* * :
-功能：处理标记内容。

- **方法 `void FindPreviousTextObject()`* * :
-功能：查找前一个文本对象。

- **方法 `void AddCharInfoByLRDirection(wchar_t wChar, const CharInfo & info)`* * :
-功能：按从左到右的方向添加字符信息。

- **方法 `void AddCharInfoByRLDirection(wchar_t wChar, const CharInfo & info)`* * :
-功能：按从右到左的方向添加字符信息。

- **方法 `TextOrientation GetTextObjectWritingMode(const CPDF_TextObject * pTextObj) const`* * :
-功能：获取文本对象的书写模式。

- **方法 `TextOrientation FindTextlineFlowOrientation() const`* * :
-功能：查找文本行的流向。

- **方法 `void AppendGeneratedCharacter(wchar_t unicode, const CFX_Matrix & form_matrix, bool use_temp_buffer)`* * :
-功能：追加生成的字符。

- **方法 `void SwapTempTextBuf(size_t iCharListStartAppend, size_t iBufStartAppend)`* * :
-功能：交换临时文本缓冲区。

- **方法 `WideString GetTextByPredicate(const std::function<bool(const CharInfo&)>&predicate) const`* * :
-功能：根据给定的谓词提取文本。

### 成员变量

- `UnownedPtr<const CPDF_Page > const m_pPage`: 指向 `CPDF_Page` 的未拥有指针。
- `DataVector<TextPageCharSegment > m_CharIndices`: 存储字符段的信息。
- `std::deque<CharInfo> m_CharList`: 存储字符信息的双端队列。
- `std::deque<CharInfo> m_TempCharList`: 存储临时字符信息的双端队列。
- `WideTextBuffer m_TextBuf`: 存储文本内容的宽文本缓冲区。
- `WideTextBuffer m_TempTextBuf`: 存储临时文本内容的宽文本缓冲区。
- `UnownedPtr<const CPDF_TextObject > m_pPrevTextObj`: 指向前一个文本对象的未拥有指针。
- `CFX_Matrix m_PrevMatrix`: 存储前一个变换矩阵。
- `const bool m_rtl`: 指示是否使用从右到左的文本布局。
- `const CFX_Matrix m_DisplayMatrix`: 存储显示变换矩阵。
- `std::vector<CFX_FloatRect> m_SelRects`: 存储选择矩形。
- `std::vector<TransformedTextObject> mTextObjects`: 存储已变换的文本对象。
- `TextOrientation m_TextlineDir`: 存储文本行的方向。
- `CFX_FloatRect m_CurlineRect`: 存储当前行的矩形。

### 总结

`CPDF_TextPage` 类在 PDFium 中扮演着重要角色，它不仅负责从 PDF 页面中提取文本内容，还提供了丰富的接口来操作和查询这些文本信息。通过 `CharInfo` 内部类，可以方便地访问每个字符的详细属性，确保了对文本内容的精确控制。此外，`CPDF_TextPage` 还支持多种文本布局和方向，能够处理复杂的 PDF 文档结构，为开发者提供了强大的文本处理能力。



// Copyright 2016 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#ifndef CORE_FPDFTEXT_CPDF_TEXTPAGE_H_
#define CORE_FPDFTEXT_CPDF_TEXTPAGE_H_

#include <stdint.h>

#include <deque>
#include <functional>
#include <optional>
#include <vector>

#include "core/fpdfapi/page/cpdf_pageobjectholder.h"
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/fx_coordinates.h"
#include "core/fxcrt/fx_memory_wrappers.h"
#include "core/fxcrt/unowned_ptr.h"
#include "core/fxcrt/widestring.h"
#include "core/fxcrt/widetext_buffer.h"

class CPDF_FormObject;
class CPDF_Page;
class CPDF_TextObject;

struct TextPageCharSegment {
  int index;
  int count;
};

FX_DATA_PARTITION_EXCEPTION(TextPageCharSegment);

class CPDF_TextPage {
 public:
  enum class CharType : uint8_t {
    kNormal,
    kGenerated,
    kNotUnicode,
    kHyphen,
    kPiece,
  };

  class CharInfo {
   public:
    CharInfo();
    CharInfo(CharType char_type,
             uint32_t char_code,
             wchar_t unicode,
             CFX_PointF origin,
             CFX_FloatRect char_box,
             CFX_Matrix matrix,
             CPDF_TextObject* text_object);
    CharInfo(const CharInfo&);
    ~CharInfo();

    CharType char_type() const { return char_type_; }
    void set_char_type(CharType char_type) { char_type_ = char_type; }

    uint32_t char_code() const { return char_code_; }

    wchar_t unicode() const { return unicode_; }
    void set_unicode(wchar_t unicode) { unicode_ = unicode; }

    const CFX_PointF& origin() const { return origin_; }

    const CFX_FloatRect& char_box() const { return char_box_; }

    const CFX_Matrix& matrix() const { return matrix_; }

    const CPDF_TextObject* text_object() const { return text_object_; }
    CPDF_TextObject* text_object() { return text_object_; }

   private:
    CharType char_type_ = CharType::kNormal;
    wchar_t unicode_ = 0;  // Above `char_code_` to potentially pack tighter.
    uint32_t char_code_ = 0;
    CFX_PointF origin_;
    CFX_FloatRect char_box_;
    CFX_Matrix matrix_;
    UnownedPtr<CPDF_TextObject> text_object_;
  };

  CPDF_TextPage(const CPDF_Page* pPage, bool rtl);
  ~CPDF_TextPage();

  int CharIndexFromTextIndex(int text_index) const;
  int TextIndexFromCharIndex(int char_index) const;
  size_t size() const { return m_CharList.size(); }
  int CountChars() const;

  // These methods CHECK() to make sure |index| is within bounds.
  const CharInfo& GetCharInfo(size_t index) const;
  CharInfo& GetCharInfo(size_t index);
  float GetCharFontSize(size_t index) const;
  CFX_FloatRect GetCharLooseBounds(size_t index) const;

  std::vector<CFX_FloatRect> GetRectArray(int start, int count) const;
  int GetIndexAtPos(const CFX_PointF& point, const CFX_SizeF& tolerance) const;
  WideString GetTextByRect(const CFX_FloatRect& rect) const;
  WideString GetTextByObject(const CPDF_TextObject* pTextObj) const;

  // Returns string with the text from |m_TextBuf| that are covered by the input
  // range. |start| and |count| are in terms of the |m_CharIndices|, so the
  // range will be converted into appropriate indices.
  WideString GetPageText(int start, int count) const;
  WideString GetAllPageText() const { return GetPageText(0, CountChars()); }

  int CountRects(int start, int nCount);
  bool GetRect(int rectIndex, CFX_FloatRect* pRect) const;

 private:
  enum class TextOrientation {
    kUnknown,
    kHorizontal,
    kVertical,
  };

  enum class GenerateCharacter {
    kNone,
    kSpace,
    kLineBreak,
    kHyphen,
  };

  enum class MarkedContentState { kPass = 0, kDone, kDelay };

  struct TransformedTextObject {
    TransformedTextObject();
    TransformedTextObject(const TransformedTextObject& that);
    ~TransformedTextObject();

    UnownedPtr<CPDF_TextObject> m_pTextObj;
    CFX_Matrix m_formMatrix;
  };

  void Init();
  bool IsHyphen(wchar_t curChar) const;
  void ProcessObject();
  void ProcessFormObject(CPDF_FormObject* pFormObj,
                         const CFX_Matrix& form_matrix);
  void ProcessTextObject(const TransformedTextObject& obj);
  void ProcessTextObject(CPDF_TextObject* pTextObj,
                         const CFX_Matrix& form_matrix,
                         const CPDF_PageObjectHolder* pObjList,
                         CPDF_PageObjectHolder::const_iterator ObjPos);
  GenerateCharacter ProcessInsertObject(const CPDF_TextObject* pObj,
                                        const CFX_Matrix& form_matrix);
  // Returns whether to continue or not.
  bool ProcessGenerateCharacter(GenerateCharacter type,
                                const CPDF_TextObject* text_object,
                                const CFX_Matrix& form_matrix);
  void ProcessTextObjectItems(CPDF_TextObject* text_object,
                              const CFX_Matrix& form_matrix,
                              const CFX_Matrix& matrix);
  const CharInfo* GetPrevCharInfo() const;
  std::optional<CharInfo> GenerateCharInfo(wchar_t unicode,
                                           const CFX_Matrix& form_matrix);
  bool IsSameAsPreTextObject(CPDF_TextObject* pTextObj,
                             const CPDF_PageObjectHolder* pObjList,
                             CPDF_PageObjectHolder::const_iterator iter) const;
  bool IsSameTextObject(CPDF_TextObject* pTextObj1,
                        CPDF_TextObject* pTextObj2) const;
  void CloseTempLine();
  MarkedContentState PreMarkedContent(const CPDF_TextObject* pTextObj);
  void ProcessMarkedContent(const TransformedTextObject& obj);
  void FindPreviousTextObject();
  void AddCharInfoByLRDirection(wchar_t wChar, const CharInfo& info);
  void AddCharInfoByRLDirection(wchar_t wChar, const CharInfo& info);
  TextOrientation GetTextObjectWritingMode(
      const CPDF_TextObject* pTextObj) const;
  TextOrientation FindTextlineFlowOrientation() const;
  void AppendGeneratedCharacter(wchar_t unicode,
                                const CFX_Matrix& form_matrix,
                                bool use_temp_buffer);
  void SwapTempTextBuf(size_t iCharListStartAppend, size_t iBufStartAppend);
  WideString GetTextByPredicate(
      const std::function<bool(const CharInfo&)>& predicate) const;

  UnownedPtr<const CPDF_Page> const m_pPage;
  DataVector<TextPageCharSegment> m_CharIndices;
  std::deque<CharInfo> m_CharList;
  std::deque<CharInfo> m_TempCharList;
  WideTextBuffer m_TextBuf;
  WideTextBuffer m_TempTextBuf;
  UnownedPtr<const CPDF_TextObject> m_pPrevTextObj;
  CFX_Matrix m_PrevMatrix;
  const bool m_rtl;
  const CFX_Matrix m_DisplayMatrix;
  std::vector<CFX_FloatRect> m_SelRects;
  std::vector<TransformedTextObject> mTextObjects;
  TextOrientation m_TextlineDir = TextOrientation::kUnknown;
  CFX_FloatRect m_CurlineRect;
};

#endif  // CORE_FPDFTEXT_CPDF_TEXTPAGE_H_
